using System;
using System.Threading;
using System.IO.Ports;
using System.Text;

namespace codebase
{
    public enum FOURD
    {
        ACK                     = 0x06,
        NAK                     = 0x15,
        ATTEMPTDELAY            = 3000,
        VISIANSWERSIZE          = 6,
        BUFFERSIZE              = 256,
        BAUDRATEDELAY           = 50
    }

    public class FourDSerial
    {
        private byte[] bytes;
        private SerialPort sr;
        private bool useSendBuffer = true;
        private const int sendBufferSize = 256;
        private int bufferCount = 0;

        public FourDSerial(SerialPort port)
        {
            if (useSendBuffer) bytes = new byte[sendBufferSize];
            sr = port;
        }

        public void sendByte(byte data)
        {
            //Debug.Print("OUT:" + data.ToString());

            if (useSendBuffer)
            {
                bytes[bufferCount] = data;
                bufferCount++;
            }
            else
            {
                if (bytes == null)
                {
                    bytes = new byte[1];
                    bytes[0] = data;
                }
                else
                {
                    byte[] _bytes = new byte[bytes.Length + 1];
                    Array.Copy(bytes, _bytes, bytes.Length);
                    _bytes[_bytes.Length - 1] = data;
                    bytes = new byte[_bytes.Length];
                    Array.Copy(_bytes, bytes, _bytes.Length);
                }
            }
        }

        public void send()
        {
            if (useSendBuffer)
            {
                sr.Write(bytes, 0, bufferCount);
                bufferCount = 0;
            }
            else
            {
                sr.Write(bytes, 0, bytes.Length);
                bytes = null;
            }
        }

        public int sendAndGetACK()
        {
            send();

            return getACK();
        }

        public int getByte()
        {
            if (waitForData(1))
            {
                byte[] data = new byte[1];
                int ret = sr.Read(data, 0, 1);
                return (int)data[0];
            }
            else
            {
                return -1;
            }
        }

        public int getACK()
        {
            int ack = getByte();
            return ack == -1 ? (int)FOURD.NAK : ack;
        }

        public int getWord()
        {
            if (waitForData(2))
            {
                byte[] data = new byte[2];
                int ret = sr.Read(data, 0, 2);
                return (int)(data[0] << 8) | data[1];
            }
            else
            {
                return 0;
            }
        }

        public int getResponse()
        {
            int ack = sendAndGetACK();
            if (ack == (int)FOURD.ACK)
            {
                int ret = getWord();
                return ret;
            }

            return 0;
        }

        long last;
        public bool waitForData(int length)
        {
            last = DateTime.Now.Ticks / 10000;
            while (sr.BytesToRead < length)
            {
                long now = DateTime.Now.Ticks / 10000;
                if (now - last >= (int)FOURD.ATTEMPTDELAY)
                {
                    //Debug.Print("[FOURD][DATA SYNC PROBLEM]");
                    return false;
                };
            }

            return true;
        }
    }
}
